/**
 * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.achartengine.chart;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.achartengine.model.Point;
import org.achartengine.model.SeriesSelection;

/**
 * PieChart Segment Selection Management.
 */
public class PieMapper implements Serializable {

	private static final long serialVersionUID = -5113305101102656354L;

	private List<PieSegment> mPieSegmentList = new ArrayList<PieSegment>();

	private int mPieChartRadius;

	private int mCenterX, mCenterY;

	/**
	 * Set PieChart location on screen.
	 * 
	 * @param pieRadius
	 * @param centerX
	 * @param centerY
	 */
	public void setDimensions(int pieRadius, int centerX, int centerY) {
		mPieChartRadius = pieRadius;
		mCenterX = centerX;
		mCenterY = centerY;
	}

	/**
	 * If we have all PieChart Config then there is no point in reloading it
	 * 
	 * @param datasetSize
	 * @return true if cfg for each segment is present
	 */
	public boolean areAllSegmentPresent(int datasetSize) {
		return mPieSegmentList.size() == datasetSize;
	}

	/**
	 * Add configuration for a PieChart Segment
	 * 
	 * @param dataIndex
	 * @param value
	 * @param startAngle
	 * @param angle
	 */
	public void addPieSegment(int dataIndex, float value, float startAngle,
			float angle) {
		mPieSegmentList
				.add(new PieSegment(dataIndex, value, startAngle, angle));
	}

	/**
	 * Clears the pie segments list.
	 */
	public void clearPieSegments() {
		mPieSegmentList.clear();
	}

	/**
	 * Fetches angle relative to pie chart center point where 3 O'Clock is 0 and
	 * 12 O'Clock is 270degrees
	 * 
	 * @param screenPoint
	 * @return angle in degress from 0-360.
	 */
	public double getAngle(Point screenPoint) {
		double dx = screenPoint.getX() - mCenterX;
		// Minus to correct for coord re-mapping
		double dy = -(screenPoint.getY() - mCenterY);

		double inRads = Math.atan2(dy, dx);

		// We need to map to coord system when 0 degree is at 3 O'clock, 270 at
		// 12
		// O'clock
		if (inRads < 0)
			inRads = Math.abs(inRads);
		else
			inRads = 2 * Math.PI - inRads;

		return Math.toDegrees(inRads);
	}

	/**
	 * Checks if Point falls within PieChart
	 * 
	 * @param screenPoint
	 * @return true if in PieChart
	 */
	public boolean isOnPieChart(Point screenPoint) {
		// Using a bit of Pythagoras
		// inside circle if (x-center_x)**2 + (y-center_y)**2 <= radius**2:

		double sqValue = (Math.pow(mCenterX - screenPoint.getX(), 2) + Math
				.pow(mCenterY - screenPoint.getY(), 2));

		double radiusSquared = mPieChartRadius * mPieChartRadius;
		boolean isOnPieChart = sqValue <= radiusSquared;
		return isOnPieChart;
	}

	/**
	 * Fetches the SeriesSelection for the PieSegment selected.
	 * 
	 * @param screenPoint
	 *            - the user tap location
	 * @return null if screen point is not in PieChart or its config if it is
	 */
	public SeriesSelection getSeriesAndPointForScreenCoordinate(
			Point screenPoint) {
		if (isOnPieChart(screenPoint)) {
			double angleFromPieCenter = getAngle(screenPoint);

			for (PieSegment pieSeg : mPieSegmentList) {
				if (pieSeg.isInSegment(angleFromPieCenter)) {
					return new SeriesSelection(0, pieSeg.getDataIndex(),
							pieSeg.getValue(), pieSeg.getValue());
				}
			}
		}
		return null;
	}
}
